package handler

import (
	"github.com/project-flogo/core/data/coerce"
)

type EdgeChannelDataStoreSettings struct {
	Addr      string `md:"addr" json:"addr,omitempty"`
	DB        int    `md:"db" json:"db,omitempty"`
	Password  string `md:"password" json:"password,omitempty"`
	KeyPrefix string `md:"keyPrefix" json:"keyPrefix,omitempty"`
}

type MetricDataStoreSettings struct {
	Addr      string `md:"addr" json:"addr,omitempty"`
	DB        int    `md:"db" json:"db,omitempty"`
	Password  string `md:"password" json:"password,omitempty"`
	KeyPrefix string `md:"keyPrefix" json:"keyPrefix,omitempty"`
}

type Settings struct {
	MetricDataStore      map[string]interface{} `md:"metricDataStore"`
	EdgeChannelDataStore map[string]interface{} `md:"edgeChannelDataStore"`
}

type Input struct {
	Command string                 `md:"command,required"`
	Params  map[string]interface{} `md:"params"`
}

func (r *Input) FromMap(values map[string]interface{}) error {
	command, err := coerce.ToString(values["command"])
	if err != nil {
		return err
	}
	r.Command = command
	params, err := coerce.ToObject(values["params"])
	if err != nil {
		return err
	}
	r.Params = params
	return nil
}

func (r *Input) ToMap() map[string]interface{} {
	return map[string]interface{}{
		"command": r.Command,
		"params":  r.Params,
	}
}

type Result struct {
	Command  string                      `mapstructure:"command" md:"command" json:"command,omitempty"`
	Params   map[string]interface{}      `mapstructure:"params" md:"params" json:"params,omitempty"`
	Err      string                      `mapstructure:"err" md:"err" json:"err,omitempty"`
	Channels map[string]EdgeChannelState `mapstructure:"channels" md:"channels" json:"channels,omitempty"`
}

func mapToResult(m map[string]interface{}) (Result, error) {
	r := Result{}
	command, err := coerce.ToString(m["command"])
	if err != nil {
		return r, err
	}
	params, err := coerce.ToObject(m["params"])
	if err != nil {
		return r, err
	}
	str, err := coerce.ToString(m["err"])
	if err != nil {
		return r, err
	}
	channelsMap, err := coerce.ToObject(m["channels"])
	if err != nil {
		return r, err
	}
	channels := map[string]EdgeChannelState{}
	for k, v := range channelsMap {
		sm, err := coerce.ToObject(v)
		if err != nil {
			return r, err
		}
		s, err := mapToEdgeChannelState(sm)
		if err != nil {
			return r, err
		}
		channels[k] = s
	}
	r.Command = command
	r.Params = params
	r.Err = str
	r.Channels = channels
	return r, nil
}

type Output struct {
	Result Result `mapstructure:"result" md:"result" json:"result,omitempty"`
}

func (o *Output) FromMap(values map[string]interface{}) error {
	resultMap, err := coerce.ToObject(values["result"])
	if err != nil {
		return err
	}
	result, err := mapToResult(resultMap)
	if err != nil {
		return err
	}
	o.Result = result
	return nil
}

func (o *Output) ToMap() map[string]interface{} {
	channels := map[string]interface{}{}
	for k, v := range o.Result.Channels {
		channels[k] = v.ToMap()
	}
	return map[string]interface{}{
		"result": map[string]interface{}{
			"command":  o.Result.Command,
			"params":   o.Result.Params,
			"err":      o.Result.Err,
			"channels": channels,
		},
	}
}
